package com.xtedu.examproject.util;

import com.xtedu.examproject.entity.UploadedFile;
import com.xtedu.examproject.factory.BatchServiceFactory;
import com.xtedu.examproject.service.BatchDataService;
import com.xtedu.examproject.service.ExamQuestionService;
import com.xtedu.examproject.service.UploadedFileService;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;

/*
 * Author: xzy
 * Date: 2025/10/14
 * Last Modified by: xzy
 * Last Modified date: 2025/10/14
 * Description: TODO - Add file description here
 */
public class UploadUtil {
    // 上传文件目录名
    private static final String UPLOAD_DIR = "uploads";
    private static final UploadedFileService uploadedFileService = new UploadedFileService();

    /**
     * 批量上传文件 默认创建在 tomcat/webapps/项目名/uploads目录
     * 上传业务由ServletPath决定，添加需修改BathServiceFactory中的方法
     *
     * @param req  请求对象
     * @param resp 响应对象
     */
    public static void uploadFile(HttpServletRequest req, HttpServletResponse resp) {
        // 普通表单字段Map
        Map<String, String> formFields = new HashMap<>();
        // 获取应用的实际路径
        String applicationPath = req.getServletContext().getRealPath("");
        String uploadFilePath = applicationPath + UPLOAD_DIR;

        // 查看临时目录是否创建，如没有则创建
        String tempDirPath = applicationPath + "temp";
        File tempDir = new File(tempDirPath);
        if (!tempDir.exists()) {
            tempDir.mkdirs();
        }
        // 设置临时目录位置
        req.setAttribute("jakarta.servlet.context.tempdir", tempDir);

        // 创建上传目录
        File uploadDir = new File(uploadFilePath);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }

        try {
            PrintWriter writer = resp.getWriter();
            // 处理每个上传的文件
            for (Part part : req.getParts()) {
                // 获取文件名
                // String filename = part.getSubmittedFileName();
                String fileName = getFileName(part);

                // 只处理文件类型的Part（排除普通表单字段）
                if (fileName != null && !fileName.isEmpty()) {
                    // 生成唯一文件名避免覆盖
                    String uniqueFileName = generateUniqueFileName(fileName);

                    // 获取文件扩展名
                    String fileExtension = getFileExtension(fileName);

                    // 验证文件类型
                    if (!isAllowedFileType(fileExtension)) {
                        writer.println("不允许的文件类型: " + fileExtension);
                        continue;
                    }

                    // 构建完整的文件路径
                    String filePath = uploadFilePath + File.separator + uniqueFileName;

                    // 保存文件
                    part.write(filePath);

                    // 获取文件信息
                    long fileSize = part.getSize();
                    String contentType = part.getContentType();
                    int examId = req.getParameter("examId") == null ? 1: Integer.parseInt(req.getParameter("examId"));
                    // 生成文件信息对象
                    UploadedFile uploadedFile = new UploadedFile(null, fileName, uniqueFileName, fileSize, contentType, new Timestamp(System.currentTimeMillis()), filePath, examId);
                    // 打印文件详细信息
                    writer.println("文件上传成功！\n"
                            + "原始文件名: " + uploadedFile.getOriginalName() + "\n"
                            + "保存文件名: " + uploadedFile.getSavedName() + "\n"
                            + "文件大小: " + formatFileSize(uploadedFile.getFileSize()) + "\n"
                            + "文件类型: " + uploadedFile.getContentType() + "\n"
                            + "保存路径: " + uploadedFile.getUploadPath() + "\n\n");
                    // 保存文件信息到数据库并处理题目导入
                    saveFileInfoToDatabase(uploadedFile, req);
                } else {
                    // 处理普通表单字段
                    String fieldName = part.getName();
                    String fieldValue = new BufferedReader(
                            new InputStreamReader(part.getInputStream(), StandardCharsets.UTF_8))
                            .lines()
                            .collect(Collectors.joining("\n"));
                    // 表单字段值存入Map
                    formFields.put(fieldName, fieldValue);
                }
            }
        } catch (IOException | ServletException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从Part的header中获取文件名
     */
    private static String getFileName(Part part) {
        // 从上传文件中解析是否为文件还是普通表单字段
        String contentDisposition = part.getHeader("content-disposition");
        String[] elements = contentDisposition.split(";");

        for (String element : elements) {
            if (element.trim().startsWith("filename")) {
                return element.substring(element.indexOf('=') + 1).trim()
                        .replace("\"", "");
            }
        }
        return null;
    }

    /**
     * 生成唯一的文件名
     */
    private static String generateUniqueFileName(String originalFileName) {
        String timestamp = String.valueOf(System.currentTimeMillis());
        String random = UUID.randomUUID().toString().substring(0, 8);
        String extension = getFileExtension(originalFileName);

        return timestamp + "_" + random + "." + extension;
    }

    /**
     * 获取文件扩展名
     */
    static String getFileExtension(String fileName) {
        if (fileName == null || fileName.lastIndexOf(".") == -1) {
            return "";
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
    }

    /**
     * 检查文件类型是否允许
     */
    private static boolean isAllowedFileType(String extension) {
        String[] allowedExtensions = {"jpg", "jpeg", "png", "gif", "pdf", "doc",
                "docx", "txt", "xls", "xlsx", "xlsm", "xlsb", "csv", "ppt", "pptx", "zip", "rar"};

        for (String allowed : allowedExtensions) {
            if (allowed.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 格式化文件大小显示
     */
    private static String formatFileSize(long size) {
        if (size < 1024) {
            return size + " B";
        } else if (size < 1024 * 1024) {
            return String.format("%.2f KB", size / 1024.0);
        } else {
            return String.format("%.2f MB", size / (1024.0 * 1024));
        }
    }

    /**
     * 保存文件信息到数据库并处理题目导入
     */
    private static void saveFileInfoToDatabase(UploadedFile uploadedFile, HttpServletRequest req) {
        try {
            // 1. 解析上传的文件并导入题目
            List<Map<String, Object>> data = parseDataFromFile(uploadedFile.getUploadPath(), uploadedFile.getContentType());

            // 2. 保存文件信息到数据库
            uploadedFileService.insert(uploadedFile);

            // 3. 根据具体业务向表里增删数据
            BatchDataService batchDataService = BatchServiceFactory.getBatchDataService(req);
            int[] results = batchDataService.insertBatch(data);
            System.out.println("成功导入 " + results.length + " 道题目");

        } catch (BatchUpdateException e) {
            int[] successfulResults = e.getUpdateCounts();
            int successCount = 0;
            for (int result : successfulResults) {
                if (result >= 0) { // SUCCESS_NO_INFO 也会返回正值
                    successCount++;
                }
            }
            System.err.println("批处理执行部分失败，成功导入 " + successCount + " 道题目");
        } catch (Exception e) {
            System.err.println("数据库操作失败或空引用: " + e.getMessage());
        }
    }

    /**
     * 根据文件类型解析题目数据
     */
    private static List<Map<String, Object>> parseDataFromFile(String filePath, String contentType) throws IOException {
        List<Map<String, Object>> data = new ArrayList<>();

        if (contentType.contains("excel") || filePath.endsWith(".xlsx") || filePath.endsWith(".xls")) {
            // 解析Excel文件
            data = parseExcelFile(filePath);
        } else if (filePath.endsWith(".csv")) {
            // 解析CSV文件
            data = parseCsvFile(filePath);
        } else if (contentType.contains("word") || filePath.endsWith(".docx")) {
            // 解析Word文件
            data = parseWordFile(filePath);
        }

        return data;
    }

    /**
     * 解析Excel文件
     */
    private static List<Map<String, Object>> parseExcelFile(String filePath) {
        List<Map<String, Object>> questions = new ArrayList<>();

        try {
            FileInputStream fis = new FileInputStream(filePath);
            Workbook workbook = WorkbookFactory.create(fis);
            Sheet sheet = workbook.getSheetAt(0);

            // 读取第一行作为标题行
            Row headerRow = sheet.getRow(0);
            Map<String, Integer> columnMapping = new HashMap<>();

            if (headerRow != null) {
                // 根据标题自动建立列映射
                for (int i = 0; i < headerRow.getLastCellNum(); i++) {
                    Cell cell = headerRow.getCell(i);
                    String headerName = getCellValueAsString(cell);
                    columnMapping.put(headerName, i);
                }
            }

            // 从第二行开始读取数据
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row != null) {
                    Map<String, Object> question = new HashMap<>();

                    // 根据列映射动态读取数据
                    for (Map.Entry<String, Integer> entry : columnMapping.entrySet()) {
                        String fieldName = entry.getKey();
                        Integer columnIndex = entry.getValue();
                        question.put(fieldName, getCellValueAsString(row.getCell(columnIndex)));
                    }

                    questions.add(question);
                }
            }
            workbook.close();
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return questions;
    }

    /**
     * 解析CSV文件（支持动态字段映射）
     */
    private static List<Map<String, Object>> parseCsvFile(String filePath) throws IOException {
        List<Map<String, Object>> questions = new ArrayList<>();

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            boolean isFirstLine = true;
            List<String> headers = new ArrayList<>();

            while ((line = reader.readLine()) != null) {
                String[] values = line.split(",");

                if (isFirstLine) {
                    // 读取标题行
                    for (String header : values) {
                        headers.add(header.trim());
                    }
                    isFirstLine = false;
                    continue;
                }

                if (values.length >= headers.size()) {
                    Map<String, Object> question = new HashMap<>();
                    // 根据标题动态映射字段
                    for (int i = 0; i < headers.size(); i++) {
                        String fieldName = headers.get(i);
                        String value = values[i].trim();

                        // 根据字段名决定是否转换为整数
                        if ("type_id".equals(fieldName) || "course_id".equals(fieldName) || "state".equals(fieldName)) {
                            question.put(fieldName, parseInteger(value));
                        } else {
                            question.put(fieldName, value);
                        }
                    }
                    questions.add(question);
                }
            }
        }

        return questions;
    }


    /**
     * 解析Word文件（支持动态字段映射）
     */
    private static List<Map<String, Object>> parseWordFile(String filePath) {
        List<Map<String, Object>> questions = new ArrayList<>();

        try {
            FileInputStream fis = new FileInputStream(filePath);
            XWPFDocument document = new XWPFDocument(fis);
            List<XWPFParagraph> paragraphs = document.getParagraphs();

            if (paragraphs.size() > 0) {
                // 读取第一组作为标题
                List<String> headers = new ArrayList<>();
                if (paragraphs.size() >= 6) {
                    for (int i = 0; i < 6; i++) {
                        headers.add(paragraphs.get(i).getText().trim());
                    }
                }

                // 处理数据行（跳过标题行）
                for (int i = 6; i < paragraphs.size(); i += 6) {
                    if (i + 5 < paragraphs.size()) {
                        Map<String, Object> question = new HashMap<>();

                        // 根据标题动态映射字段
                        for (int j = 0; j < Math.min(6, headers.size()); j++) {
                            String fieldName = headers.get(j);
                            String value = paragraphs.get(i + j).getText();

                            // 根据字段名决定是否转换为整数
                            if ("type_id".equals(fieldName) || "course_id".equals(fieldName) || "state".equals(fieldName)) {
                                question.put(fieldName, parseInteger(value));
                            } else {
                                question.put(fieldName, value);
                            }
                        }
                        questions.add(question);
                    }
                }
            }

            document.close();
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return questions;
    }


    /**
     * 获取单元格值为字符串
     */
    private static String getCellValueAsString(Cell cell) {
        if (cell == null) return "";

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf((long) cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            default:
                return "";
        }
    }

    /**
     * 获取单元格值为整数
     */
    private static Integer getCellValueAsInteger(Cell cell) {
        if (cell == null) return null;

        switch (cell.getCellType()) {
            case NUMERIC:
                return (int) cell.getNumericCellValue();
            case STRING:
                try {
                    return Integer.parseInt(cell.getStringCellValue());
                } catch (NumberFormatException e) {
                    return null;
                }
            default:
                return null;
        }
    }

    /**
     * 解析字符串为整数
     */
    private static Integer parseInteger(String value) {
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    /**
     * 驼峰命名转下划线命名
     */
    private static String camelToUnderscore(String camelCase) {
        if (camelCase == null || camelCase.isEmpty()) {
            return camelCase;
        }

        StringBuilder result = new StringBuilder();
        for (int i = 0; i < camelCase.length(); i++) {
            char ch = camelCase.charAt(i);
            if (Character.isUpperCase(ch)) {
                if (i > 0) {
                    result.append("_");
                }
                result.append(Character.toLowerCase(ch));
            } else {
                result.append(ch);
            }
        }
        return result.toString();
    }
}
